package com.paimeng.lucence;

import com.paimeng.bean.News_info;
import com.paimeng.utils.Highlight;
import com.paimeng.utils.SortByHotIndex;
import com.paimeng.utils.SortByTime;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryparser.classic.MultiFieldQueryParser;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.search.*;
import org.apache.lucene.search.highlight.Highlighter;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;

import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

/**
 * @author: 潘辉
 * @Title: Searcher
 * @ProjectName: paimeng
 * @Description: 查询索引
 * @date: 2021/6/17 16:43
 */
public class Searcher {

    //查询索引数据
    //1 创建读取目录对象
    //2 创建索引读取工具
    //3 创建索引搜索工具
    //4 创建查询解析器
    //5 创建查询对象
    //6 搜索数据
    //7 各种操作
    public static List<News_info> search(String indexPath, String queryStr, int pageSize, int curPageIndex, String sortMethod) {

        boolean isWildcardSearch = WildCardMatch.isWildCard(queryStr);
        List<News_info> results = new ArrayList<News_info>();



        try {
            File indexpath = new File(indexPath);
            if (!indexpath.exists()) {
                indexpath.mkdirs();
            }
            // 设置要查询的索引目录
            Path dir = Paths.get(indexPath);
            //1、创建或打开索引目录
            Directory directory = FSDirectory.open(dir);
            //2、创建DirectoryReader索引读取工具
            DirectoryReader dReader = DirectoryReader.open(directory);
            //3、 创建IndexSearcher索引搜索工具
            IndexSearcher indexSearcher = new IndexSearcher(dReader);
            //4、创建分词器对象
            Analyzer analyzer = new StandardAnalyzer();
            //5、创建查询对象
            Query query = null;
            // 搜索数据,两个参数：查询条件对象要查询的最大结果条数
            // 返回的结果是 按照匹配度排名得分前N名的文档信息（包含查询到的总条数信息、所有符合条件的文档的编号信息）。
            TopDocs hits = null;

            if (isWildcardSearch) {
                //通配符查询
                System.out.println("通配符查询");
                Term t1 = new Term("date", queryStr);
                WildcardQuery query1 = new WildcardQuery(t1);
                Term t2 = new Term("title", queryStr);
                WildcardQuery query2 = new WildcardQuery(t1);
                Term t3 = new Term("content", queryStr);
                WildcardQuery query3 = new WildcardQuery(t2);

                /*
                 * BooleanClause.Occur.MUST:与运算
                 * BooleanClause.Occur.SHOULD:或运算
                 * BooleanClause.Occur.MUST_NOT:非运算
                 * BooleanClause.Occur.FILTER:相当于与运算，但是不参与评分。
                 */

                BooleanClause bc1 = new BooleanClause(query1, BooleanClause.Occur.SHOULD);
                BooleanClause bc2 = new BooleanClause(query2, BooleanClause.Occur.SHOULD);
                BooleanClause bc3 = new BooleanClause(query3, BooleanClause.Occur.SHOULD);

                //BooleanQuery（组合查询）
                /*
                 * 布尔查询：
                 * 	布尔查询本身没有查询条件，可以把其它查询通过逻辑运算进行组合！
                 * 交集：Occur.MUST + Occur.MUST
                 * 并集：Occur.SHOULD + Occur.SHOULD
                 * 非：Occur.MUST_NOT
                 */
                //得到最终的综合的查询条件
                query = new BooleanQuery.Builder().add(bc1).add(bc2).add(bc3).build();


                //两个参数，查询条件对象，要查询的最大查询条数
                //返回的结果是按照匹配度得分前N名的文档信息（包含查询到的总条数信息，所有符合条件的文档的编号信息）
                hits = indexSearcher.search(query, 10);
            } else {
                //普通查询
                System.out.println("普通查询");
                String[] fields = {"date", "title", "content"};
                BooleanClause.Occur[] clauses = {BooleanClause.Occur.SHOULD, BooleanClause.Occur.SHOULD, BooleanClause.Occur.SHOULD};
                //得到最终的综合的多字段查询条件
                query = MultiFieldQueryParser.parse(queryStr, fields, clauses, analyzer);

                //6、搜索数据
                hits = indexSearcher.search(query, 1000);
            }

            // 获取得分文档对象（ScoreDoc）数组.SocreDoc中包含：文档的编号、文档的得分
            ScoreDoc[] scoreDocs = hits.scoreDocs;

            System.out.println("匹配 '" + queryStr + "'，总共查询到" + hits.totalHits + "个文档");

            if (curPageIndex < 1) {
                curPageIndex = 1;
            }
            int begin = pageSize * (curPageIndex - 1);
            int end = (int) Math.min(begin + pageSize, hits.totalHits.value);
            String title = null;
            String content = null;
            //准备高亮显示工具
            Highlighter highlighter = Highlight.getHighligth(query);
            for (int i = begin; i < end; i++) {
                //取出文档的编号
                int docID = scoreDocs[i].doc;

                //依据文档编号取出Document对象
                Document doc = indexSearcher.doc(docID);
                title = highlighter.getBestFragment(analyzer, "title", doc.get("title"));
                if (title == null) {
                    title = doc.get("title");
                }
                content = highlighter.getBestFragment(analyzer, "content", doc.get("content"));
                if (content == null) {
                    content = doc.get("content");
                }

                News_info news = new News_info();
                news.setTitle(title);
                news.setUrl(doc.get("url"));
                news.setDate(doc.get("date"));
                news.setContent(content);
                news.setSrcFrom(doc.get("srcFrom"));
                news.setHotIndex(Integer.parseInt(doc.get("hotIndex")));
                news.setContent(content);

                results.add(news);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return results;
    }


    public static List<News_info> searchHot(String indexPath, String queryStr) throws IOException, ParseException {

        // 设置要查询的索引目录
        Path dir = Paths.get(indexPath);
        //1、创建索引目录对象
        Directory directory = FSDirectory.open(dir);

        //2、创建indexSearcher索引读取工具
        DirectoryReader dReader = DirectoryReader.open(directory);
        //3、创建索引搜索工具
        IndexSearcher indexSearcher = new IndexSearcher(dReader);
        List<News_info> result = new ArrayList<News_info>();
        //4、创建查询解析器,两个参数：默认要查询的字段的名称，创建分词器对象
        Analyzer analyzer = new StandardAnalyzer();

        File indexpath = new File(indexPath);
        if (!indexpath.exists()) {
            indexpath.mkdirs();
        }

        String[] fields = {"date", "title"};
        //Occur.SHOULD表示或的关系，取查询并集，
        BooleanClause.Occur[] clauses = {BooleanClause.Occur.SHOULD, BooleanClause.Occur.SHOULD};
        //5、创建查询对象
        //MultiFieldQueryParser提供多字段查找
        Query query = MultiFieldQueryParser.parse(queryStr, fields, clauses, analyzer);
        //6、搜索数据
        TopDocs hits = indexSearcher.search(query, 1000);
        //获取得分文档对象（ScoreDoc）数组.SocreDoc中包含：文档的编号、文档的得分
        ScoreDoc[] scoreDocs = hits.scoreDocs;

        //System.out.println("匹配 '"+queryStr+"'，总共查询到"+ hits.totalHits +"个文档");

        int begin = 0;
        int end = 10;
        for (int i = begin; i < end; i++) {

            int docID = scoreDocs[i].doc;
            // 根据编号去找文档
            Document doc = indexSearcher.doc(docID);
            News_info news = new News_info();
            news.setTitle(doc.get("title"));
            news.setUrl(doc.get("url"));
            news.setDate(doc.get("date"));
            news.setSrcFrom(doc.get("srcFrom"));
            news.setHotIndex(Integer.parseInt(doc.get("hotIndex")));
            news.setContent(doc.get("content"));
            //news.printNews();
            result.add(news);
        }

        return result;
    }

}
